chdkfandomcom-20200222-history
UBASIC/TutorialScratchpad
Since nobody is presently working on making a more elaborate section of how to write scripts for CHDK, this might be a good place to do some brainstorming on the right way to use the uBASIC programming language and available commands. Eventually some of these miight become detailed enough to add to the more official /CHDK/uBASIC/ main page. I haven't done any programming in BASIC for about 30 years, and I am totally unfamiliar with uBASIC, but I'm going to do my best to try to at least get some'''thing started in the way of a tutorial that others with no programming knowledge could follow to write their own scripts. If anyone sees some errors (there will be many), and can correct, elaborate, or clarify on some section already started '''please do so. If you can add your own section on an area that has not been covered yet, again, please do so. ---- =The Script Header= :When viewing scripts you'll often see the opening section look something like this: @title Interval shooting @param a Shoot count @default a 5 @param b Interval (Minutes) @default b 0 Let's break down what each of those lines mean and how they are used by CHDK. ;@title Your Script Title This is the title that will appear when you have the script loaded in CHDK and go to "Scripting Parameters" menu selection. It will appear under the line "----Current Script----" as well as in the lower-left corner of your viewfinder when you are in mode. Keep your title short (24 characters or less). Otherwise the title will cover up the label. ;@param x (label) ;@default x n :This is where you will define the begining values of any variables used in your script. These are often used to set how many exposures you want, how long of a delay you want, how many bracketing steps you want, etc. These variables can be changed by the end-user from the "Scripting Parameters" menu items. In that sub-menu, they will appear under the line "----Script Parameters-----" :@param x (label) :The "x'''" in that line will be one of any lower-case latin letter from '''a to j'''. The (label) is the text string that will appear in your "----Script Parameters----" list, to let the end user know which of the variables they are changing (i.e. number of shots, how many steps, etc.). : :Up to 10 @param statments, user-controllable variables, may be used in any one script. :@default x n''' :This statement sets up the default, or beginning value of your (lower-case letter) variable, where "x'" is the variable from the @param statement above, and "'n" is the default value to start with. This value is only used when script is loaded first time. ;Notes: :If there is no @title command the filename of script is used. If there are no @param commands HDK assumes that there are three adjustable variables: a''', '''b and c'''. After your default variable values have been defined here, it is good to add some lines right after this section to ensure those numbers will be used in case the user has input 0 (zero) for some value that needs to be higher (or lower). You will see this in scripts as: if '''a<2 then let a'''=5 :If your default value that you wanted the user to start out at for parameter variable '''a was 5, then if they left that setting at 0 (zero) or 1, then this will automatically increase that variable's value back up to 5. After you have set up your variable parameters, then comes the brunt of your script, the part that does the actual work and tells the camera what to do, when to do it, and what buttons or commands need to be executed. Since we are working with a very small subset of the larger uBASIC programming language, it might be good to list and explain only those that are availble to the CHDK script writer. ---- =The Basics of BASIC Programming= Logic Commands :All programs are designed to mindlessly repeat some commands. In order to make them work in the proper order, and the correct number of sequences, they have to be contained in some simple recurring loops and counters. Testing for when some condition has been met, before it can go onto the next command, or finally end the program (script). There are several ways this can be done in BASIC. By using numeric counters, and loops. There are some built-in commands to simplify these tasks. The LET Command :This one is simple. If you see a command that says "let a''' = 2" then that's exactly what happens. It defines the value of 2 to the variable '''a. The IF / THEN / ELSE Commands :These are used to test for the truth of a certain condition. IF something is true, THEN this takes place, ELSE (otherwise) do this if it is not true. :A simple example: if a''' > 2 then goto "subroutine1" :If in your script, the variable '''a has been assigned to a value greater-than 2, then the script will jump to the labeled subroutine1. if a''' >2 then goto "subroutine1" else "subroutine2" :In this case if '''a is NOT greater than the value of 2, your program will jump to subroutine2. :The conditional expressions allowed in uBASIC are: =''' (equal to), '''> (greater than), <''' (less than), '''<> (not equal to), <= (less than or equal to), >= (greater than or equal to) The FOR / TO / NEXT Commands :These are used to set up simple loops. You will often see them in scripts as in this example: for n'''=2 to '''a sleep t''' print "Shoot", '''n, "of", a''' shoot next '''n :The first line "for n'''=2 to '''a" means that the "for / to / next" loop will run while variable-'n' equals the sequence of numbers of 2 up to whatever the number variable-'a' has been assigned to. The commands that take place in the loop are containted between the FOR statement and the NEXT statment. "next n" tells the loop to go back to the beginning "for ..." statement until the the a''' value has been reached. For example: for '''n=1 to 10 print "This is line number", n''' next '''n This will produce the sequence of: This is line number 1 This is line number 2 This is line number 3 . . . This is line number 9 This is line number 10 And then that loop will end and go onto the next sequence of commands. Subroutines using GOSUB (and related GOTO) Commands and Labels Sub-Routines :For complex programming tasks, it is often helpful to split the program into smaller subroutines that can be called with gosub and goto commands. A sub-routine can be nearly anything but it is generally used for a set of commands that will be called-up more than once. Instead of writing the same set of commands over and over again you put that code into a subroutine and then call it up from within the main program by using gosub "label" or goto "label". Subroutines are generally placed after the main code. A labeled subroutine that will be called by gosub "label" needs to end with the return comand, to tell the script to jump out of that section of code and return back to from where it was called. :GOSUB and GOTO are similar but you should refrain from using GOTO unless you know what you are doing. GOSUB will always return from a subroutine as soon as it reaches the RETURN command. GOTO does not behave this way. GOTO should only be used when you are going to jump to a section of the script one time and under special circumstances. GOSUB and GOTO Examples :A simple GOSUB example (the subroutine's label and subroutine are in bold): for x=1 to 10 gosub "display" next x :display ''' '''print x return : :Due to a known bug, you might need to add a space char right after the label (":label "), otherwise you might get an "Unk Label"-error. (More on Unk in the debugging section.) :A longer example that would capture 3 images with increased ISO settings would look something like this: shoot for i=1 to 3 gosub "incISO" shoot next i for i=1 to 3 gosub "decISO" next i end :incISO click "menu" more clicks return :decISO click "menu" more clicks return :An example using the GOTO command taken from an endless intervalometer script. NOTE: This situation creates an endless loop. Until you manually override the script it will continue. This is generally considered BAD FORM! Any script should include/end-with all the commands to reset the camera to its original configuration prior to running the script, and properly end with the END command. Do not do this kind of thing unless you have a special need for it and know what you are doing. @title Interval Shooting Non-stop @param a Interval (Minutes) @default a 0 @param b Interval (Seconds) @default b 5 @param c Interval (10th Seconds) @default c 0 t=a*60000+b*1000+c*100 if t<100 then let t=5000 n=1 print "Interval shooting." print "Until you interrupt it." print "Use with caution." sleep 1000 goto "shot" ' ':shot print "Shot number", n shoot n=n+1 sleep t goto "shot" (author's note: this section needs some help I think) The Print Command :This will print whatever text follows the statement, to your LCD or EVF display while the script is running. :Syntax: print "24 characters of text" :You are limted to 24 characters being displayed in any one line of text. You may also include the values of variables or integer-equations in your print statement. :Examples: rem Print total duration of interval to viewfinder print "Total time:", t*a/60000; "min", t*a%60000/1000; "sec" sleep 1000 rem Start actual camera operation in a loop print "Shoot 1 of", a shoot for n=2 to a sleep t print "Shoot", n, "of", a shoot next n The Sleep Command :This pauses the script to allow some action to take place, or to delay when the next action should occur. :Syntax: sleep x :Where x''' is any variable or whole number. The value is in 1000ths of a second. :Example: '''sleep 1500 means to pause for 1.5 seconds. The REM Command :The "rem" (which stands for "remark") command is sometimes used to place a comments in a script. It is only used as a rem'''inder for the person writing or viewing the sciprt. Like an internal note. This command is not exectued nor seen when the script is run. However, keep in mind that scripts for CHDK can be only 2k (2 thousand characters) in length. Too many REM statements can slow down your script as well as taking up valuable space. :An (overzealous) example of REM commands in a script '''rem Interval shooting @title Interval shooting @param a Shoot count @default a 10 @param b Interval (Minutes) @default b 0 @param c Interval (Seconds) @default c 10 rem Calculate 1000ths of seconds from variables t=b*60000+c*1000 rem Sets some default variables to initial values if a<2 then let a=10 if t<1000 then let t=1000 rem Print total duration of session in viewfinder print "Total time:", t*a/60000; "min", t*a%60000/1000; "sec" rem Delay actual shooting so they can read the above print statement. sleep 1000 rem Start actual camera operation in a loop print "Shoot 1 of", a shoot for n=2 to a sleep t print "Shoot", n, "of", a rem This takes the actual exposure. shoot next n rem Ends this script end :REM statements can always be removed from a script if you feel there are too many or unneeded. Removing a rem line will not impact the operation of the script in any way (other than speeding it up and using up less memory space). The End Command :This should be the last line in your script. It tells the script to cease all operations and return camera control back to you. Before end'ing a script, it is good-form to always reset any camera settings that the script took control of during initialization of your routine or during. So that the end user doesn't have to undo all the keypresses and menu changes that the script created. ---- =Math Expressions allowed in uBASIC= :Addition, Subtraction +, - :Multiplication, Division *, / :Remainder % :< Less Than :> Greater Than := Equal ;[Added by GrAnd: I'm afraid, but CHDK uBasic supports only integer type of variables and expressions. Just '+, '-', *', '/, %', '|, &', '<, >''' and '''= operations. And just simple assignment ='.)] ---- Most of the expressions are easy to understand, but the '% (remainder) operation might like a short explanation. :Example: Let's say you have computed a number to equal how many seconds something will take for a duration. Such as s=(some math expression) Where s''' is being assigned the number of seconds computed. :Now you want to display that as minutes and seconds. You will need a print statement such as: :print "Total Time:" , s/60; "min", (the remainder of s/60); "sec" :There is a very simple way to do this using the % command. Think of % as "the remainder of s being divided by". So all you need to do is have this print statement: :print "Total Time:" , s/60; "min", s%60; "sec" :If '''s had the value of 328 seconds, then this would print out to :Total Time: (328/60)='5 min' (the remainder of 328/60)='28 sec' :or more simply :Total Time: 5 min 28 sec ---- ;Some Unconventional Limitations: This version of uBASIC does not (currently) support unary -; so you cannot write "let b=-5" instead you have to write "let b=0-5" Normal math expression hierarchies are not followed. :Normally we assume that operations such as + and - will be performed before any * and / operations. This is not the case in this uBASIC. You will have to be careful on what order you put your math operations. Also parenthetical or nested parenthetical math expression are not allowed in some instances. A calculation like print (x*y)+z/60 will result in an error being generated. :Due to these limitations you will have break down such operations into more simple one-line calculations if you want to use these values in more lengthy expressions. Example, instead of: :print (x*y)+z/60 :Use: :p=x*y :q=p+z :print q/60 :(Perhaps someone can clarify this further, because in my Ultra Intervalometer script I can use a parenthetical expression in a subroutine, but not in a print statement. This can be confusing! :-) With the only way to test a script is to continually swap out an SD card between computer and camera, trial & error can turn into hours if not days.) ---- =Camera Operation Commands= These commands are designed to allow your script to control your camera much like you would manually. Nearly anything you can do by pressing buttons on your camera with your own fingers, you can also do automatically with these script commands. The complexity and time-line of your script is only limited by your imagination and trying to creatively keep your script under the 2,000 character limit. These are the only commands available (at this time). They are always used after the click command and must be bracketed by double-quotes. (Example: click "zoom_out".) The one exception is the shoot command. This is used by itself without the click statment. shoot :Records an image. :This command is similar to the click "shoot_full" command (see below), but it waits for the camera to perform some normally automatic actions, such as charging the flash, etc. For example: if in AUTO, P, Tv, Av, or any SCN modes, using the "shoot" command causes the camera to check focus and exposure for each shot. When "shoot" is used in intervalometer scripts this far surpasses the camera's own built-in intervalometer in that the camera only sets exposure and focus once for the initial exposure, as if it was only using the "click 'shoot_full'" command. This "shoot" command in an intervalometer script allows it to compensate for all the things that can change over the course of many minutes and hours. For more precise manual control of the camera in scripts, see the click "shoot_half", click "shoot_full", (and the yet to be added get_tv, set_tv, set_tv_rel, get_av, set_av, set_av_rel) commands below. click "up", click "down", click "left", click "right" :Clicks the respective directional button of your "Omni-Selector" (navigational buttons). click "set" :Clicks the set button. click "shoot_half" :Clicks the shutter-release in the half-press position. This is often used to lock focus, exposure, or other camera settings. click "shoot_full" :Clicks the shutter-release button completely, irregardless if the camera has finished charging the flash or other normally automatic camera operations. :Note: on the S3 IS there is no way to engage the video-record mode at this time. As this is on a separate button independent of any other menus or controls that can be accessed by the presently available commands. Some of the sample-scripts available are for intervalometer-video sessions. These will not work as written. If ran on the S3 IS they will only take a single still-frame image each time the video-mode is supposed to be started and stopped by the script. click "zoom_in", click "zoom_out" :Initiates your camera's zoom control one zoom-step at a time. The A-Series cameras have 9 or 15 zoom steps (0 to 8/14), and the S3 IS has 129 zoom steps (0 to 128). This command may require an extra sleep command after each zoom step. The S3 IS camera implements this command very slowly. Here's an example of how it may be used in a loop: for s=2 to a for n=1 to b print "Zooming-in ", n; "..." click "zoom_in" sleep 600 next n print "Shoot", s, "of", a shoot next s :Note the 0.6 second sleep command after each zoom_in step. click "menu" :Clicks the menu button. :This is used to alter some of the cameras settings that can only be set through the record menus, to set up the camera before a script-session, or during. :Example: :slowsync click "menu" sleep 400 click "down" sleep 400 click "down" sleep 400 click "down" sleep 400 click "right" sleep 400 click "menu" sleep 400 return :This :slowsync" sub-routine will initialize the camera's flash setting into slow-sync mode. Note also the sleep commands, giving your camera time to respond to the new settings between each directional button-press. Button-press delay times may be camera specific. (Meaning it might be a good idea to set up a user-defined variable for these in some scripts to save on script-size and make the script more adaptable to more makes and models of cameras. A note could be made in the accompanying script's documentation on what button-press delays are needed per make and model of camera.) click "display" :Clicks the camera's display button. click "print" :Clicks the camera's print button. (Note: clicks the shortcut button for the S3 IS.) click "erase" :Clicks the camera's erase button. (Note: clicks the FUNC'''tion button for the S3 IS.) :This will often be used to select some shooting parameters like exposure-compensation, movie frame-rates, white-balance settings, ... any of the options that can be reached by pressing this button on your camera. It is then used in conjunction with directional button-presses to choose the desired settings. :Example: @title EXP bracketing @param a Number of ñsteps @default a 2 @param b Step size (1/3EV) @default b 3 if a<1 then let a=2 if b<1 then let b=3 sleep 1000 print "Preparing..." click "erase" for n=1 to a*b click "left" next n for s=1 to a*2 print "Shoot", s, "of", a*2+1 shoot for n=1 to b click "right" next n next s print "Shoot", a*2+1, "of", a*2+1 shoot print "Finalizing..." for n=1 to a*b click "left" next n click "erase" end :In this "Exposure Bracketing" script, if you follow the embedded button-presses, you'll see that your Exposure Compensation setting is being selected by using the '''click "erase" command. The click "right" and click "left" commands are moving the Exposure compensation settings to the right and left (more exposure and less exposure), just as you would if you were doing this manually from one shot to the next. ---- The set_tv, get_tv, etc commands :There are several commands for getting and seting the aperture and the speed. They only work in Manual mode; well you can change the settings in any mode, but they are effective in manual mode, probably also in Av and Tv modes). I put a test script for these commands in the "user written sripts" The commands are get_tv target set_tv_rel val set_tv val get_av target set_av_rel val set_av val :Target is the name of a variable (a, b, ..z), val is an expression. :An example of setting and printing the values. :set_get set_av c set_tv b print "AV,TV set to",c,b sleep 1000 click "shoot_half" sleep 100 get_av n get_tv m print "AV,TV got",n,m end :You can change the settings relative to existing values: rem increase light (1/3+1/3 steps) set_tv_rel 0-1 set_av_rel 0-1 shoot end :This migt make bracketing easierand faster :For A710is the Av and Tv settings provide the following actual values; roughly +/-1 setting means +/-1/3 EV change. set_av set_tv set_tv set_tv 0 2.8 -13 15" 3 0.5" 19 1/80 10 3.2 -12 13" 4 0.4" 20 1/100 11 3.5 -11 10" 5 0.3" 21 1/125 12 4.0 -10 ? 6 1/4 22 1/160 13 4.5 -9 8" 7 1/5 23 1/200 14 5.0 -8 6" 8 1/6 24 1/250 15 5.6 -7 5" 9 1/8 25 1/320 16 6.3 -6 4" 10 1/10 26 1/400 17 7.1 -5 3.2" 11 1/13 27 1/500 18 8.0 -4 2.5" 12 1/15 28 1/640 -3 2" 13 1/20 29 ??? -2 1.6" 14 1/25 30 1/800 -1 1.3" 15 1/30 31 1/1000 0 1" 16 1/40 32 1/1250 1 0.8" 17 1/50 33 1/1600 2 0.6" 18 1/60 34 1/2000 :It would be interesting to know about the other models. ---- =Debugging: the Unk Alert= :This tiny version of uBASIC includes some debugging help. When running a script with a bad command you might sometimes get an Unk statement printed in the top-left corner of your EVF or LCD display. This will alert you to why your coding didn't work, albeit in a very abreviated format. :Some exmaples of what you might see, and what they will mean: :(insert examples and explanations here) Some unexpected behaviour of uBASIC :These are my observations, which might be inaccurate. Stebu do not "execute" labels if a<0 then goto "nega" let a=5*6 goto "nega" If this line is left out and a>=0 then an error (unk statement or unk label) will be generated :nega ---- TutorialScratchpad